local function Fn()
    local Fx = Class()


    function Fx:Init(NPC_BASE_LIB)
        ---------------------------------------------------------------------------------------------------------------------------


        -- if NPC_BASE_LIB.inst == nil or not NPC_BASE_LIB.inst:HasTag("player") then
        --     return
        -- end

        --------------------------------------------------------------------------------------------------------------------------------------
        --- --- 获取事件然后进入队列
        function NPC_BASE_LIB:SPAWN__Calculator_For_Probability()
            ------- 用来得事件概率表，从配置读取数据并计算
            -- TUNING.NPC_CONFIG.BASE_MATERIAL_SUPPLIERS
            -- TUNING.NPC_CMD_TABLE
            local NPC_CMD_TABLE = {}
            ----- deep copy
            for event_name, event_cmd in pairs(TUNING.NPC_CMD_TABLE) do
                NPC_CMD_TABLE[event_name] = event_cmd
            end
            -----------------------------------------------------------------------------------------------------
            ----- DLC角色检查 和专属事件 插入列表
            local NPC_CMD_TABLE_DLC_CHARACTERS = TUNING.NPC_CMD_TABLE_DLC_CHARACTERS
            local DLC_CHARACTERS_LIST = self:___Get_DLC_Character_List()

            for DLC_NAME, flag in pairs(DLC_CHARACTERS_LIST) do
                if flag == true then
                    local temp_dlc_cmd_table = NPC_CMD_TABLE_DLC_CHARACTERS[DLC_NAME]
                    for event_name, event_cmd in pairs(temp_dlc_cmd_table) do
                        NPC_CMD_TABLE[event_name] = event_cmd
                    end

                end
            end

            -----------------------------------------------------------------------------------------------------


            ------- 第一步，计算除了 npc_event_give_basic_supplies 以外的总概率参数
            local other_event_all_num = 0
            for event_name, cmd_table in pairs(NPC_CMD_TABLE) do
                if event_name ~= "npc_event_give_basic_supplies" then
                    other_event_all_num = other_event_all_num + cmd_table.Probability
                end
            end

            ------ 第二步，根据总概率参数反推 npc_event_give_basic_supplies 的参数
            local base_prob = TUNING.NPC_CONFIG.BASE_MATERIAL_SUPPLIERS ----- 0 ~ 1

            if other_event_all_num ~= 0 then
                -- local temp_Prob = 0
                -- temp_Prob / (other_event_all_num + temp_Prob )= TUNING.NPC_CONFIG.BASE_MATERIAL_SUPPLIERS
                local temp_Prob = base_prob*other_event_all_num / (1 - base_prob)
                temp_Prob = math.ceil(temp_Prob)
                NPC_CMD_TABLE["npc_event_give_basic_supplies"].Probability = temp_Prob
            end


            ------- 第三步，创建 table 集合
            local Probability_event_table = {}
            for event_name, cmd_table in pairs(NPC_CMD_TABLE) do
                for i = 1, cmd_table.Probability, 1 do
                    table.insert(Probability_event_table,event_name)
                end
            end
            
            --- ---- 得到目标概率表
            -- for k, v in pairs(Probability_event_table) do
            --     print(k,v)
            -- end
            self.tempData.Probability_event_table = Probability_event_table
            self.tempData.NEW_CMD_TABLE = NPC_CMD_TABLE
        end


        function NPC_BASE_LIB:SPAWN__Get_Random_Event_Name()
            if self.tempData.Probability_event_table and type(self.tempData.Probability_event_table) == "table" then
                local ret_event = self:GetRandom(self.tempData.Probability_event_table)
                return ret_event
            else
                return "npc_event_give_basic_supplies"
            end
        end


        function NPC_BASE_LIB:SPAWN__Save_CMD_Table_To_Data()
            --- -- -- 第一步 ： 得到概率表
            if self.tempData.Probability_event_table == nil then
                self:SPAWN__Calculator_For_Probability()
            end

            --------- 第二步 ： 根据概率表得到 随机事件名字 str
            local event_name = self:SPAWN__Get_Random_Event_Name()

            --------- 第三步 ： 得到 CMD_TABLE
            local ret_cmd_table = TUNING.NPC_CMD_TABLE[event_name]
            if self.tempData.NEW_CMD_TABLE then
                ret_cmd_table = self.tempData.NEW_CMD_TABLE[event_name]   --- 插入了DLC角色事件的 CMD TABLE
            end
            if ret_cmd_table == nil then
                print("Error !!! Get NPC CMD_TABLE error !")
                return
            end
            ----------------------------------------------------------------
            ------- 深拷贝事件CMD TABLE ，不然某个事件一直是同一个NPC
            ret_cmd_table = deepcopy(ret_cmd_table)
            ----------------------------------------------------------------
            ret_cmd_table.event_name = event_name   ------- event_name 注入 CMD TABLE
            -------- 第四步 ：赋予NPC_INST名字到table，以及保存到事件队列

            if ret_cmd_table.NPC_NAME == nil then                
                ret_cmd_table.NPC_NAME = self:Get_Random_Npc_Name(ret_cmd_table.ban)

            elseif ret_cmd_table.NPC_NAME and type(ret_cmd_table.NPC_NAME) == "table" then

                local ret_name = self:GetRandom(ret_cmd_table.NPC_NAME)
                ret_cmd_table.NPC_NAME = ret_name

            end

            self.inst.components.npc_everything_data:Save_Spawn_CMD_Table(ret_cmd_table)

        end


        function NPC_BASE_LIB:SPAWN__Daily_Get_CMD_Event_Init()
            local inst = self.inst
            if inst == nil or not inst:HasTag("player") then
                return
            end
            inst:ListenForEvent("npc_spawn.cmd_get",function()
                inst:DoTaskInTime(1,function()
                    inst.components.npc_everything_data:Clean_Spawn_CMD_Table() --- 每天清除一次，避免NPC扎堆出现
                    local DAILY_NPC_NUM = TUNING.NPC_CONFIG and TUNING.NPC_CONFIG.DAILY_NPC_NUM or 1
                    if DAILY_NPC_NUM < 1 then --- 概率刷新处理。
                        DAILY_NPC_NUM = 1
                    end
                    for i = 1, DAILY_NPC_NUM, 1 do
                        inst.components.npc_base_lib:SPAWN__Save_CMD_Table_To_Data()
                    end
                    print("NPC_SPAWN_EVENT_QUEUE is Ready")

                end)
            end)

            inst:WatchWorldState("cycles", function()   ------------------- 每天刷新数量
                inst:PushEvent("npc_spawn.cmd_get")                
            end)
        end


        --------------------------------------------------------------------------------------------------------------------------------------
        ------------ 时间队列初始化

        function NPC_BASE_LIB:SPAWN__Get_Time_To_Queue()
            local npc_num = self.inst.components.npc_everything_data:Get_Spawn_Queue_Num()
            if npc_num < 1 then ----------- 每天刷新NPC数量
                npc_num = 1
            end
            ---------------------------------------------------------------------------------------------------------
            --- 概率出现处理
            local DAILY_NPC_NUM = TUNING.NPC_CONFIG and TUNING.NPC_CONFIG.DAILY_NPC_NUM or 1
            if DAILY_NPC_NUM < 1 then
                if math.random(100)/100 <= DAILY_NPC_NUM then
                    npc_num = 1
                else
                    npc_num = 0
                end
            end
            ---------------------------------------------------------------------------------------------------------

            
            local Start_Base_Time = 5
            local End_Base_Time = 460   --- 一天的秒数为 480
            if npc_num == 1 then
                local ret_spawn_time = math.random(Start_Base_Time,End_Base_Time)
                self.inst.components.npc_everything_data:Save_Spwan_Time(ret_spawn_time)
                return
            elseif npc_num == 2 then
                local mid_time = math.ceil(  (Start_Base_Time + End_Base_Time)/2  )
                self.inst.components.npc_everything_data:Save_Spwan_Time(math.random(Start_Base_Time, mid_time))
                self.inst.components.npc_everything_data:Save_Spwan_Time(math.random(mid_time, End_Base_Time))
                return
            elseif npc_num == 3 then
                local time_split_num = math.ceil( (Start_Base_Time + End_Base_Time) / npc_num  )
                self.inst.components.npc_everything_data:Save_Spwan_Time(math.random(Start_Base_Time, Start_Base_Time + time_split_num))
                self.inst.components.npc_everything_data:Save_Spwan_Time(math.random(Start_Base_Time + time_split_num, Start_Base_Time + 2*time_split_num ))
                self.inst.components.npc_everything_data:Save_Spwan_Time(math.random(Start_Base_Time + 2*time_split_num, End_Base_Time ))
                return
            elseif npc_num == 4 then
                local time_split_num = math.ceil( (Start_Base_Time + End_Base_Time) / npc_num  )
                self.inst.components.npc_everything_data:Save_Spwan_Time(math.random(Start_Base_Time, Start_Base_Time + time_split_num))
                self.inst.components.npc_everything_data:Save_Spwan_Time(math.random(Start_Base_Time + time_split_num, Start_Base_Time + 2*time_split_num ))
                self.inst.components.npc_everything_data:Save_Spwan_Time(math.random(Start_Base_Time + 2*time_split_num, Start_Base_Time + 3*time_split_num ))
                self.inst.components.npc_everything_data:Save_Spwan_Time(math.random(Start_Base_Time + 3*time_split_num, End_Base_Time ))
                return
            end
                    

        end


        function NPC_BASE_LIB:SPAWN__Time_Queue_Init()
            local inst = self.inst
            if inst == nil or not inst:HasTag("player") then
                return
            end
            inst:ListenForEvent("npc_spawn.time_get",function()
                inst:DoTaskInTime(2,function()  --- 比NPC 的队列慢一点
                    inst.components.npc_everything_data:Clean_Spawn_Time()
                    inst.components.npc_base_lib:SPAWN__Get_Time_To_Queue()
                    print("NPC_SPAWN_TIME_QUEUE is Ready")
                end)
            end)
            inst:WatchWorldState("cycles", function()   ------------------- 每天刷新数量
                inst:PushEvent("npc_spawn.time_get")                
            end)
        end

        --------------------------------------------------------------------------------------------------------------------------------------
        --------- 刷新计时器初始化

        function NPC_BASE_LIB:SPAWN__Spawn_Timer_Start()
            local inst = self.inst



            inst:DoPeriodicTask(5,function()    ---------- 每5秒检查一次

                local ret_time =  inst.components.npc_everything_data:Add("NPC_SPAWN_TIMER",5) ---- 计时器累加
                -- print("Time : ",ret_time)
                local spawn_time = inst.components.npc_everything_data:Get_Spawn_Time(true)     --- no_pop ，不移出队列的形式读取下一次刷新时间
                if ret_time >= spawn_time then   --------- 如果到达刷新时间
                    local NPC_CMD_TABLE = inst.components.npc_everything_data:Get_Spawn_CMD_Table(true) -- no_pop ,不移出队列的形式读取下一次NPC_CMD_TABLE
                    if inst.components.npc_base_lib:SPAWN__SpawnReadyCheck(inst,NPC_CMD_TABLE) == true then ---- 如果到达刷新条件
                        local temp_time = inst.components.npc_everything_data:Get_Spawn_Time()  -- 把时间移出队列
                        local temp_cmd_table = inst.components.npc_everything_data:Get_Spawn_CMD_Table()    -- 把NPC_CMD_TABLE 移出队列
                        inst.components.npc_base_lib:SPAWN__NPC_AND_ANNOUNCE(NPC_CMD_TABLE) -- 开始刷新NPC事件
                    end

                end

            end)

            print("NPC_SPAWN_TIMER : START")
        end

        --------------------------------------------------------------------------------------------------------------------------------------
        function NPC_BASE_LIB:ALL_NPC_EVENT_TASK_INIT() ---------- 玩家加载时候的总入口
            self:SPAWN__Daily_Get_CMD_Event_Init() ----------  获取NPC CMD TABLE 给队列 ---- 延迟1秒
            self:SPAWN__Time_Queue_Init()         ----------  获取新的刷新时间队列       ---- 延迟2秒
            self.inst:DoTaskInTime(3,function()     ----------- 计时器 延迟 3秒
                self.inst.components.npc_base_lib:SPAWN__Spawn_Timer_Start()
            end)
            self.inst:WatchWorldState("cycles", function()   ------------------- 重置计时器
                self.inst.components.npc_everything_data:Set("NPC_SPAWN_TIMER",0)
            end)

            self.inst:ListenForEvent("npc_spawn.debug",function()
                self.inst.components.npc_everything_data:Set("NPC_SPAWN_TIMER",0)
                self.inst:PushEvent("npc_spawn.cmd_get")
                self.inst:PushEvent("npc_spawn.time_get")
            end)
        end
        ---------------------------------------------------------------------------------------------------------------------------
        function NPC_BASE_LIB:Is_Point_In_Camp(thePoint)
            if thePoint == nil or thePoint.x == nil then
                return false
            end
            local Bonus_Points_List = {
                ["firepit"] = 5,
                ["tent"] = 3,
                ["cage"] = 1,
                ["lightningrod"] = 2,
                ["madsciencelab"] = 3,
                ["prototyper"] = 5,
                ["giftmachine"] = 5,
                ["chest"] = 2,
                ["door"]    = 5,
                ["fence"]  = 2,
                ["stewer"] = 5,
                ["beebox"] = 5,
                ["icebox"] = 5,
                ["dragonflyfurnace"] = 5,
                ["mushroom_light2"] = 3,
                ["mushroom_light"] = 3,
                ["cookpot"] =  4,
                ["heavy"] = 4,
                ["dining_table"] = 4,
            }

            local x = thePoint.x
            local y = 0
            local z = thePoint.z


            local function Point_Get(tarInst)
                if Bonus_Points_List[tostring(tarInst.prefab)] then
                    return Bonus_Points_List[tostring(tarInst.prefab)]
                end
                for tag, p in pairs(Bonus_Points_List) do
                    if tarInst:HasTag(tag) then
                        return p
                    end
                end
                return 0
            end
            
            local canthavetags = { "INLIMBO","flight", "invisible"}
            local targetInsts = TheSim:FindEntities(x, 0, z, 25, nil, canthavetags, nil)
            local check_point_ret = 0
            for k, tempInst in pairs(targetInsts) do
                check_point_ret = check_point_ret + ( Point_Get(tempInst) or 0)
                if check_point_ret > 25 then
                    return true
                end
            end



            return false
        end
        local function IsNearDanger(theplayer)
            local function IsNearDanger_old(traveller)
                -- code from fast traveller Mod : workshop-1530801499
                local hounded = TheWorld.components.hounded
                if hounded ~= nil and (hounded:GetWarning() or hounded:GetAttacking()) then
                    return true
                end
                local burnable = traveller.components.burnable
                if burnable ~= nil and (burnable:IsBurning() or burnable:IsSmoldering()) then
                    return true
                end
                if traveller:HasTag("spiderwhisperer") then
                    return FindEntity(traveller, 15, function(target)
                        return (target.components.combat ~= nil and
                                target.components.combat.target == traveller) or
                                (not (target:HasTag("player") or target:HasTag("spider")) and
                                    (target:HasTag("monster") or target:HasTag("pig")))
                    end, nil, nil, {"monster", "pig", "_combat"}) ~= nil
                end
                return FindEntity(traveller, 15, function(target)
                    return (target.components.combat ~= nil and
                            target.components.combat.target == traveller) or
                            (target:HasTag("monster") and not target:HasTag("player"))
                end, nil, nil, {"monster", "_combat"}) ~= nil
            end

            if theplayer:HasTag("playerghost") then
                return true
            end
            if IsNearDanger_old(theplayer) then
                return true
            end
    
            local x , y, z =  theplayer.Transform:GetWorldPosition()
            local ents = TheSim:FindEntities(x, y, z, 20, nil, {"NPC"}, {"player"})
            for k, v in pairs(ents) do
                if v and v.isplayer then
                    if IsNearDanger_old(v) then
                        return true
                    end
                end
            end
            local monsters = TheSim:FindEntities(x, 0, z, 35, nil, nil, {"epic","animal","monster"})
            for k, tempMonster in pairs(monsters) do
                if tempMonster then
                    if tempMonster.components.combat and
                    (tempMonster.components.combat.target and tempMonster.components.combat.target.isplayer)
                    then
                        return true
                    end
                    if tempMonster:HasTag("epic") and tempMonster.components.health and tempMonster.components.health:GetPercent() < 0.95 then
                        return true
                    end
                end
            end

            local arena = TheSim:FindEntities(x, y, z, 20, {"npc_item_pigman_arena_spell_coin"}, nil, nil)
            if #arena > 0 then
                return true
            end
            
            return false
        end        
        --------------- 检查 和刷新
        function NPC_BASE_LIB:SPAWN__SpawnReadyCheck(inst,NPC_CMD_TABLE) ------  刷新时机，地点 检查
                                -- -- -- 用到的参数
                                -- _table["npc_event_give_basic_supplies"] = {
                                --     event_name = "npc_event_give_basic_supplies",    -- 用于刷debuff 的时候，不用事先准备，概率计算器会自己添加
                                --     NPC_NAME = nil,                                  ---- nil 的时候 随机列表里的npc ，
                                                                                        ---- NPC_NAME == "player" 的时候刷新在玩家身上 
                                                                                        ---- prefab 名字，刷新指定的 inst 实体
                                --                                                      ---- NPC_NAME = {"wilson","wolfgang","woodie","webber"} -- 指定某些随机
                                --     time = 100,                                      ---- time out 
                                --     Probability = 5,                                 ---- 概率
                                --     ban = {"wilson","woodie"},                       ---- 禁用列表，注意名字
                                --     CampProtect = nil,                               ----- 保护营地，true 的时候检查玩家位置
                                --     Unable_To_Refuse = nil,                          ----- true 的时候无法被玩家赶走
                                --     SpawnDistance = nil,                             ----- 和玩家的刷新距离
                                --     SpawnPoint = Vector3(),                          ----- 特殊事件需要提前刷新坐标
                                --      tags = {"tag1","tag2" }                         ----- 添加tags 给npc

                                -- }
            if NPC_CMD_TABLE == nil then
                return false
            end
            local theplayer = inst
            if theplayer:HasTag("playerghost") then
                return false
            end

            if theplayer.sg and theplayer.sg.HasStateTag and theplayer.sg:HasStateTag("sleeping") then
                return false
            end

            if theplayer:HasOneOfTags({"invisible","INLIMBO","noattack","notarget"}) then
                return false
            end

            if NPC_BASE_LIB.NAME == "player" then   ---- 如果是直接放到玩家身上的
                return true
            end
            
            if theplayer.__link_npc ~= nil and theplayer.__link_npc:IsValid() then  ---- 如果当前NPC事件没结束
                print("WARNING: SpawnReadyCheck , Current NPC event is not end")
                return false
            end

            local x,y,z = inst.Transform:GetWorldPosition()

            if y > 0 then
                return false
            end

            if TheWorld.Map:IsAboveGroundAtPoint(x,0,z,false) == false then -- 不在地面上
                return false
            end

            if TheWorld.Map:IsOceanAtPoint(x,0,z,true) == true then    -- 在海上,在船上
                return false
            end

            if IsNearDanger(theplayer) then
                return false
            end

            


            --------------------------- 刷新地点营地检查    -- 如果需要检查营地且玩家在营地里
            if TUNING.NPC_CONFIG.CAMP_PROTECKTION == true and NPC_CMD_TABLE.CampProtect == true then
                -- print("info : Start Check")
                -- print("Info : CampProtect Check:",TUNING.NPC_CONFIG.CAMP_PROTECKTION,NPC_CMD_TABLE.CampProtect )

                if self:Is_Point_In_Camp(Vector3(theplayer.Transform:GetWorldPosition())) == true then
                    return false
                end
            end
            ------------------------------------------
            return true
        end
        local function Spawn_NPC_By_CMD_TABLE(inst,NPC_CMD_TABLE)
            -- -- -- 用到的参数
                                -- _table["npc_event_give_basic_supplies"] = {
                                --     event_name = "npc_event_give_basic_supplies",    -- 用于刷debuff 的时候，不用事先准备，概率计算器会自己添加
                                --     NPC_NAME = nil,                                  ---- nil 的时候 随机列表里的npc ，
                                                                                        ---- NPC_NAME == "player" 的时候刷新在玩家身上 
                                                                                        ---- prefab 名字，刷新指定的 inst 实体
                                --                                                      ---- NPC_NAME = {"wilson","wolfgang","woodie","webber"} -- 指定某些随机
                                --     time = 100,                                      ---- time out 
                                --     Probability = 5,                                 ---- 概率
                                --     ban = {"wilson","woodie"},                       ---- 禁用列表，注意名字
                                --     CampProtect = nil,                               ----- 保护营地，true 的时候检查玩家位置
                                --     Unable_To_Refuse = nil,                          ----- true 的时候无法被玩家赶走
                                --     SpawnDistance = nil,                             ----- 和玩家的刷新距离
                                --     SpawnPoint = Vector3(),                          ----- 特殊事件需要提前刷新坐标
                                --      tags = {"tag1","tag2" }                         ----- 添加tags 给npc

                                -- }
            --------------------------------------------------
            --- --- CMD TABLE INIT
            
            local NPC_NAME = NPC_CMD_TABLE.NPC_NAME
            --     NPC_NAME = nil,                              ---- nil 的时候 随机列表里的npc ，
            --                                                  ---- NPC_NAME == "player" 的时候刷新在玩家身上 
            --                                                  ---- prefab 名字，刷新指定的 inst 实体
            --                                                  ---- NPC_NAME = {"wilson_npc","wolfgang_npc","woodie_npc","webber_npc"} -- 指定某些随机 必须是 prefab name
            local event_name = NPC_CMD_TABLE.event_name or "npc_event_give_basic_supplies"
            local time = NPC_CMD_TABLE.time or 100
            local CampProtect = NPC_BASE_LIB.CampProtect ----- 保护营地，true 的时候检查玩家位置
            local Unable_To_Refuse = NPC_BASE_LIB.Unable_To_Refuse ----- true 的时候无法被玩家赶走
            local SpawnDistance = NPC_BASE_LIB.SpawnDistance or 25 ----- 和玩家的刷新距离
            local SpawnPoint = NPC_BASE_LIB.SpawnPoint ----- 特殊事件需要提前刷新坐标 -- Vector3()
            local tags = NPC_CMD_TABLE.tags


            
            local x,y,z = inst.Transform:GetWorldPosition()
            --------------------------------------------------

            if NPC_NAME == "player" and inst:HasTag("player") then
                inst:AddDebuff(event_name,event_name)
                return
            end

            --------------------------------------------------------------
            -- 第一步 ，得到 prefab 的名字，type:string
            if NPC_NAME == nil then
                inst.npc_base_lib:Get_Random_Npc_Name(NPC_CMD_TABLE.ban)
            elseif type(NPC_NAME) == "table" then
                NPC_NAME = inst.components.npc_base_lib:GetRandom(NPC_NAME)
            end
            if type(NPC_NAME) ~= "string" then
                print("Error : NPC_NAME is not string",print(unpack(NPC_CMD_TABLE)))
                return
            end

            --------------------------------------------------------------
            -- 第二步 ，第一阶段，获取 出现坐标
            if SpawnPoint == nil then
                for i = 1, 100, 1 do    --- 尝试100次获取坐标,其中后50次 随机距离
                    if i < 50 then
                        local get_pt = inst.components.npc_base_lib:GetSpawnPoint(inst,SpawnDistance)
                        if get_pt ~= nil and TheWorld.Map:IsAboveGroundAtPoint(get_pt.x,get_pt.y,get_pt.z,false) == true then
                            SpawnPoint = get_pt
                            break
                        end
                    else
                        local get_pt = inst.components.npc_base_lib:GetSpawnPoint(inst,math.random(SpawnDistance))
                        if get_pt ~= nil and TheWorld.Map:IsAboveGroundAtPoint(get_pt.x,get_pt.y,get_pt.z,false) == true then
                            SpawnPoint = get_pt
                            break
                        end
                        if math.random() < 1 then
                            print("SpawnPoint Try Times:",i)
                        end
                    end
                end
            end
            if SpawnPoint  == nil or SpawnPoint.x == nil then
                print("Error : Spawn_NPC_By_CMD_TABLE , SpawnPoint is nil")
                return
            end
            ---------------------------------------------------------------
            -- 第二步 第二阶段，检查刷新点，保护营地。 放弃第一阶段得到的数据
            if TUNING.NPC_CONFIG.CAMP_PROTECKTION == true and NPC_CMD_TABLE.CampProtect == true then
                SpawnPoint = nil
                local ret_temp_point = nil
                for i = 1, 100, 1 do
                    SpawnPoint = inst.components.npc_base_lib:GetSpawnPoint(inst,SpawnDistance)
                    if SpawnPoint and SpawnPoint.x and inst.components.npc_base_lib:Is_Point_In_Camp(SpawnPoint) ~= true and TheWorld.Map:IsAboveGroundAtPoint(SpawnPoint.x,SpawnPoint.y,SpawnPoint.z,false) == true then
                        ret_temp_point = SpawnPoint
                        break
                    end
                end
                if ret_temp_point == nil or ret_temp_point.x == nil then
                    print("Error : Spawn_NPC_By_CMD_TABLE , CAMP_PROTECKTION ")
                    return
                end
                SpawnPoint = ret_temp_point
            end
            ---------------------------------------------------------------


            ----------------------------------------------------------------
            -- 第三步 ， 创建 npc_inst 实体
            local ret_npc_inst = SpawnPrefab(NPC_NAME)
            if ret_npc_inst == nil then
                print("Error : Spawn_NPC_By_CMD_TABLE ,SpawnPrefab by NPC_NAME  error",NPC_NAME,print(unpack(NPC_CMD_TABLE)))
                return
            end

            ----------------------------------------------------------------
            -- 第四步 ，把 NPC 放到指定坐标，和添加 debuff ,link 玩家和NPC ，添加超时
            if tags ~= nil and type(tags) == "table" then
                for k, temp_tag in pairs(tags) do
                    ret_npc_inst:AddTag(tostring(temp_tag))
                end
            end
            
            ret_npc_inst:PushEvent("player_link",inst)
            ret_npc_inst.Transform:SetPosition(SpawnPoint.x,0,SpawnPoint.z)
            ret_npc_inst.components.npc_base_lib:Set_Time_Out(time)
            ret_npc_inst:AddDebuff(event_name,event_name)
            SpawnPrefab("npc_fx_spawn"):PushEvent("Set",{ pt = SpawnPoint })
            if NPC_CMD_TABLE.Unable_To_Refuse == true then
                ret_npc_inst:AddTag("Unable_To_Refuse")
            end
            

        end
        local function TheWorld_Announce_Npc_Task(inst,NPC_CMD_TABLE)
            local language = inst.components.npc_base_lib:Get_Language()

            ---------------------------------------------------------------------------------------------
            local announce_table = nil

            ---------------------------------------------------------------------------------------------
            -- -- 加载外部table
            if TUNING.NPC_ANNOUNCE_TABLE then
                if TUNING.NPC_ANNOUNCE_TABLE[language] then
                    announce_table = TUNING.NPC_ANNOUNCE_TABLE[language]
                else
                    announce_table = TUNING.NPC_ANNOUNCE_TABLE["en"]
                end
            end
            ---------------------------------------------------------------------------------------------
            if announce_table == nil then
                return
            end
            local ret_announce =  announce_table[NPC_CMD_TABLE.event_name]
            if ret_announce == nil then
                return
            end

            if type(ret_announce) == "table" then
                ret_announce = inst.components.npc_base_lib:GetRandom(ret_announce)
            end
            inst.components.npc_base_lib:Wisper(tostring(ret_announce))
        end
        ------------------------- -----------------------------------
        -- 声明并刷新NPC
        function NPC_BASE_LIB:SPAWN__NPC_AND_ANNOUNCE(NPC_CMD_TABLE)
            if not self.inst:HasTag("player") then
                return
            end
            if NPC_CMD_TABLE == nil then
                return
            end
            if type(NPC_CMD_TABLE) == "table" and NPC_CMD_TABLE.event_name == nil then
                return
            end
            TheWorld_Announce_Npc_Task(self.inst,NPC_CMD_TABLE)
            Spawn_NPC_By_CMD_TABLE(self.inst,NPC_CMD_TABLE)

        end
        ---------------------------------------------------------------------------------------------------------------------------

        function NPC_BASE_LIB:Get_Random_Npc_Name(ban)
            -- local npc_names_list = {"wilson","willow","wolfgang","wx78","wickerbottom","woodie","wes","waxwell","wathgrithr","webber","winona","warly","walter","wendy","wonkey","wagstaff_2","woodlegs"}
            local npc_names_list = TUNING.NPC_CONFIG.NPC_NAME_LIST
            local dlc_character_list = self:___Get_DLC_Character_List()
            for temp_name, flag in pairs(dlc_character_list) do
                if flag == true then
                    table.insert(npc_names_list,temp_name)
                end
            end

            if ban and type(ban) == "table" then
                local ban_list = {}
                for k, name in pairs(ban) do
                    ban[name] = true
                end
                local new_npc_names_list = {}
                for k, name in pairs(npc_names_list) do
                    if ban[name] ~= true then
                        table.insert(new_npc_names_list,name)
                    end
                end

                return self:GetRandom(new_npc_names_list).."_npc"

            else
                return self:GetRandom(npc_names_list).."_npc"
            end
        end
        ---------------------------------------------------------------------------------------------------------------------------
    end

    return Fx
end

return Fn